<template>
  <Form>
    <Row :gutter="15" style="align-items: center; margin-bottom: 5px">
      <Col :span="6">
        <Form.Item label="Git分支">
          <Select v-model:value="currentBranch" :options="branches" />
        </Form.Item>
      </Col>
      <Col :span="5">
        <Form.Item label="发布模式">
          <Select v-model:value="deployMode" @change="changeMode">
            <Select.OptGroup label="从Git分支">
              <Select.Option value="">Build</Select.Option>
              <Select.Option value="--uat">UAT</Select.Option>
              <Select.Option value="--prd">生产</Select.Option>
            </Select.OptGroup>
            <Select.OptGroup label="从版本">
              <Select.Option value="--uat -v">UAT</Select.Option>
              <Select.Option value="--prd -v">生产</Select.Option>
            </Select.OptGroup>
          </Select>
        </Form.Item>
      </Col>
      <Col :span="7" v-if="deployMode.indexOf('-v') == -1">
        <Form.Item label="发布分支">
          <Select v-model:value="currentMapping" :options="mappings" />
        </Form.Item>
      </Col>
      <template v-if="deployMode.indexOf('-v') != -1">
        <Col :span="7">
          <Form.Item label="发布版本">
            <Select v-model:value="currentVersion" :options="versions" />
          </Form.Item>
        </Col>
        <Col style="margin-left: -10px">
          <Button type="primary" title="查看镜像版本信息" shape="circle" @click="showModal = true">
            <InfoCircleOutlined />
          </Button>
        </Col>
      </template>
      <Col>
        <Button type="primary" shape="round" @click="deploy"><SendOutlined /> 发布</Button>
      </Col>
    </Row>
  </Form>
  <div class="shell">
    <p class="code">{{ script }} {{ scriptParams }}</p>
  </div>
  <div class="shell details" :style="{ maxHeight: maxHeight - 70 + 'px' }">
    <p v-for="d of deploys" v-html="replaceWhitespace(d)"></p>
  </div>
  <ImageDetail v-model:show="showModal" :detail="imageDetail" />
</template>
<script setup>
  import { ref, reactive, inject, computed, watch, watchEffect, onMounted, defineAsyncComponent } from 'vue';
  import { Row, Col, Form, Select, Button } from 'ant-design-vue';
  import { SendOutlined, InfoCircleOutlined } from '@ant-design/icons-vue';

  import { replaceWhitespace } from '@/libs/helpers';

  const ImageDetail = defineAsyncComponent(() => import('./ImageDetail.vue'));

  const props = defineProps({
    maxHeight: String | Number,
    config: {
      type: Object
    }
  });

  const $http = inject('$http');
  const $modal = inject('$modal');

  const script = ref();
  const deployMode = ref('');

  const branches = ref([]);
  const currentBranch = ref('');

  const mappings = ref([]);
  const currentMapping = ref('');

  const versions = ref([]);
  const currentVersion = ref('');

  const deploys = ref([]);
  const showModal = ref(false);
  const imageDetail = reactive({
    extra_attrs: {
      config: {
        Entrypoint: [],
        Env: [],
        ExposedPorts: {}
      }
    }
  });

  const scriptParams = computed(() => {
    if (deployMode.value.indexOf('-v') == -1) {
      return `${currentMapping.value} ${deployMode.value}`;
    }

    let mode = deployMode.value.replace('-v', '');

    return `${currentVersion.value} ${mode}`;
  });

  watch(currentVersion, () => {
    if (versions.value && versions.value.length > 0 && currentVersion.value) {
      let current = versions.value.find(v => v.value == currentVersion.value);

      imageDetail.size = current.full.size;
      imageDetail.pull_time = current.full.pull_time;
      imageDetail.push_time = current.full.push_time;
      imageDetail.extra_attrs = current.full.extra_attrs;
    }
  });

  async function getGitBranch() {
    let cmd = {
      command: props.config.GitBranch
    };

    let res = await $http.post('/api/shell/exec', cmd);

    if (res.datas) {
      branches.value = res.datas.map(d => {
        let value = d.trim();

        if (d.startsWith('*')) {
          value = value.slice(2);

          currentBranch.value = value;
        }

        return { label: d, value: value };
      });
    }
  }

  async function getMappings(script) {
    let cmd = {
      command: script
    };

    let res = await $http.post('/api/shell/exec', cmd);

    currentMapping.value = '';

    if (res.datas && res.datas.length > 2) {
      let items = res.datas.slice(1, res.datas.length - 1);

      mappings.value = items.map(m => {
        let arr = m.trim().split(' ');
        let value = arr[0].replace(/\)/gi, '');
        let label = arr[1].split('=')[1].replace(/[';]/gi, '');

        value = value == '*' ? 'Release' : value;

        if (label.toLowerCase() == currentBranch.value.toLowerCase()) {
          currentMapping.value = value;
        }

        return { label: `${label} / ${value}`, value: value };
      });

      if (deployMode.value) {
        mappings.value.unshift({ label: 'release', value: '' });
      }
    }
  }

  async function getVersions() {
    let res = await $http.get(props.config.HarborRepositoryUrl);

    if (res.datas && res.datas.length > 0) {
      versions.value = res.datas.map(d => {
        let tag = d.tags[0].name;

        return { label: `${tag}`, value: tag, full: d };
      });

      currentVersion.value = versions.value[0].value;
    }
  }

  async function changeMode(value) {
    script.value = value ? props.config.OnlineCommand : props.config.BuildCommand;

    await getMappings(value ? props.config.GetOnlineVersions : props.config.GetBuildVersions);
  }

  async function deploy() {
    let cmd = {
      command: `${script.value} ${scriptParams.value};`
    };

    let modal = $modal.info({ title: '提示', okText: '升级中...', okButtonProps: { disabled: true, visible: false }, maskClosable: false });

    deploys.value.length = 0;

    modal.update({ content: '正在执行中，请稍后...' });

    try {
      let res = await $http.post('/api/shell/exec', cmd, { hideTip: true, timeout: 600000 });
      modal.update({ content: '执行成功', type: 'success', okText: '关闭' });

      deploys.value = res.datas;
    } catch (err) {
      deploys.value = JSON.stringify(err);
    } finally {
      let handler = setInterval(() => {
        modal.destroy();

        clearInterval(handler);
      }, 1000);
    }
  }

  onMounted(async () => {});

  watchEffect(async () => {
    script.value = props.config.BuildCommand;

    let p1 = getGitBranch();
    let p2 = getMappings(props.config.GetBuildVersions);

    let p3 = getVersions();

    await Promise.all([p1, p2, p3]);
  });
</script>
<style lang="less" scoped></style>
